#include "exithandler.h"
#include "vtsystem.h"
#include "vtasm.h"
#include "app.h"
GUEST_REGS guestRegContext;

void handleRdmsr()
{
    IA32_FEATURE_CONTROL_MSR controlMsr;
    *(PULONG64)(&controlMsr)   = Asm_ReadMsr(guestRegContext.ecx);
    guestRegContext.edx =  (ULONG)(controlMsr.Reserved3);
    guestRegContext.eax =  *(PULONG)(&controlMsr);
    if (MSR_IA32_FEATURE_CONTROL==guestRegContext.ecx) {
        controlMsr.Lock=FALSE;
        guestRegContext.eax = *(PULONG)(&controlMsr);
    }
    KdPrint(("Rdmsr MsrIndex:%x - %016I64X \n",guestRegContext.ecx,controlMsr));
}

void handleWrmsr()
{
    Asm_WriteMsr(guestRegContext.ecx,guestRegContext.eax, guestRegContext.edx );
}

void HandleCPUID()
{
    _CPUID_ECX  uCPUID;
    Asm_CPUID(guestRegContext.eax, &guestRegContext.eax, &guestRegContext.ebx, &guestRegContext.ecx, &guestRegContext.edx);
    *((PULONG)&uCPUID) = guestRegContext.ecx;
    uCPUID.VMX=FALSE;
    guestRegContext.ecx=*((PULONG)&uCPUID);
}


extern ULONG VmxOffArgument;
extern ULONG VmxOffEsp, VmxOffEip;

void HandleVmCall()
{
    if (VmxOffArgument == 'VOFF')
    {
        Vmx_VmClear(vmxCpu.pVMCSRegion_PA.LowPart,vmxCpu.pVMCSRegion_PA.HighPart);
        Vmx_VmxOff();
        __asm{
            mov esp, VmxOffEsp
            jmp VmxOffEip
        }
    } else {
         LogLn("VmxOffArgument != 'VOFF'");

    }
}



void HandleCrAccess()
{
    MovCrQualification ExitQualification;
    *((PULONG)&ExitQualification) = Vmx_VmRead(EXIT_QUALIFICATION);
    switch (ExitQualification.fields.control_register)
    {
        case 0:
        case 1:
        case 2:
            LogLn("It's not doing cr3");
            __asm int 3
                    break;
        case 3:
                    switch (ExitQualification.fields.access_type)
                    {
                    case kMoveToCr:
                        Vmx_VmWrite(GUEST_CR3, *(PULONG)((ULONG)&guestRegContext + 4 * ExitQualification.fields.gp_register));
                        break;
                    case kMoveFromCr:
                        *(PULONG)((ULONG)&guestRegContext + 4 * ExitQualification.fields.gp_register) = Vmx_VmRead(GUEST_CR3);
                        break;
                    case kClts:
                    case kLmsw:
                        break;
                    default:
                        break;
                    }
                    break;
        default:
            break;

    }
}
VOID VMEntryPointWork()
{
    //退出码
    ULONG ExitReason;
    //指令长度
    ULONG ExitInstructionLength;

    ExitReason              = Vmx_VmRead(VM_EXIT_REASON);
    ExitInstructionLength   = Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN);

    guestRegContext.eflags  = Vmx_VmRead(GUEST_RFLAGS);
    guestRegContext.esp     = Vmx_VmRead(GUEST_RSP);
    guestRegContext.eip     = Vmx_VmRead(GUEST_RIP);

    switch(ExitReason)
    {
    case EXIT_REASON_CPUID:
        HandleCPUID();
        Log("EXIT_REASON_CPUID", ExitReason)
                break;

    case EXIT_REASON_VMCALL:
        HandleVmCall();
        Log("EXIT_REASON_VMCALL", ExitReason)
                break;

    case EXIT_REASON_CR_ACCESS:
        HandleCrAccess();
        //Log("EXIT_REASON_CR_ACCESS", ExitReason)
        break;

    case EXIT_REASON_MSR_READ:
        Log("EXIT_REASON_READMSR", ExitReason)
        handleRdmsr();
        break;

    case EXIT_REASON_MSR_WRITE:
        Log("EXIT_REASON_WRITEMSR", ExitReason)
        handleWrmsr();
        break;

    default:
        Log("not handled reason: %p", ExitReason);

    }

    Vmx_VmWrite(GUEST_RIP,      guestRegContext.eip += ExitInstructionLength);
    Vmx_VmWrite(GUEST_RSP,      guestRegContext.esp);
    Vmx_VmWrite(GUEST_RFLAGS,   guestRegContext.eflags);
}

void __declspec(naked) VMMEntryPoint(void)
{
    __asm{

        mov guestRegContext.eax, eax
                mov guestRegContext.ecx, ecx
                mov guestRegContext.edx, edx
                mov guestRegContext.ebx, ebx
                mov guestRegContext.esp, esp
                mov guestRegContext.ebp, ebp
                mov guestRegContext.esi, esi
                mov guestRegContext.edi, edi

                mov ax,fs
                mov fs,ax

                mov ax,gs
                mov gs,ax
    }
    VMEntryPointWork();
    __asm{
        mov  eax, guestRegContext.eax
                mov  ecx, guestRegContext.ecx
                mov  edx, guestRegContext.edx
                mov  ebx, guestRegContext.ebx
                mov  esp, guestRegContext.esp
                mov  ebp, guestRegContext.ebp
                mov  esi, guestRegContext.esi
                mov  edi, guestRegContext.edi
                jmp   Vmx_VmResume
    }

}
